﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Threading;
using System.IO;
using System.Reflection;
using AForge.Video.DirectShow;
using AForge.Controls;
using AForge.Video;
using System.Drawing;
using System.ServiceModel;
using InvRec.InvRecognitionService;
using System.Runtime.Serialization.Json;

namespace InvRec
{
    [ComVisible(true)]
    [Guid("9F1A7845-9784-4361-A9B8-56ACE847005D")]
    [ClassInterface(ClassInterfaceType.None)]
    [ComSourceInterfaces(typeof(CompleteEvent))]
    [ComDefaultInterface(typeof(ICom))]
    public class Com : UserControl, ICom, IObjectSafety
    {
        public Com()
        {
            video = new VideoSourcePlayer();
            video.Dock = DockStyle.Fill;
            this.Controls.Add(video);

            binding = new BasicHttpBinding()
            {
                MaxReceivedMessageSize = 2024000000,
                MaxBufferSize = 2024000000,
                ReaderQuotas = new System.Xml.XmlDictionaryReaderQuotas
                {
                    MaxArrayLength = 16384,
                    MaxStringContentLength = 2024000000,
                    MaxBytesPerRead = 4096,
                    MaxDepth = 32,
                    MaxNameTableCharCount = 16384
                }
            };
        }

        private VideoSourcePlayer video;
        private string savePath = Path.Combine(Path.GetTempPath(), "InvRec.jpg");
        private BasicHttpBinding binding;

        public void CaptureCam(string ms)
        {
            try
            {
                if (video.IsRunning)
                {
                    video.SignalToStop();
                    video.WaitForStop();
                    video.Stop();
                }
                else
                {
                    var currentDS = default(FilterInfo);
                    var videoDevices = new FilterInfoCollection(AForge.Video.DirectShow.FilterCategory.VideoInputDevice);
                    foreach (FilterInfo item in videoDevices)
                    {
                        if (ms == item.MonikerString)
                        {
                            currentDS = item;
                            break;
                        }
                    }
                    if (currentDS == null)
                    {
                        throw new Exception("未找到[" + ms + "]摄像设备");
                    }
                    var videoDevice = new VideoCaptureDevice(currentDS.MonikerString);
                    videoDevice.VideoResolution = videoDevice.VideoCapabilities[0];
                    video.NewFrame -= videoDevice_SnapshotFrame;
                    video.NewFrame += videoDevice_SnapshotFrame;
                    videoDevice.ProvideSnapshots = true;
                    if (videoDevice.SnapshotCapabilities.Length > 0)
                    {
                        videoDevice.SnapshotResolution = videoDevice.SnapshotCapabilities[0];
                    }
                    video.VideoSource = videoDevice;
                    video.Start();
                }
            }
            catch (Exception ex)
            {
                TriggerReadCompleteEvent(new CompleteEventArgs(false, ex.Message));
            }
        }

        // New snapshot frame is available
        private void videoDevice_SnapshotFrame(object sender, ref Bitmap image)
        {
            video.NewFrame -= videoDevice_SnapshotFrame;
            try
            {
                image.Save(savePath, System.Drawing.Imaging.ImageFormat.Jpeg);
                TriggerReadCompleteEvent(new CompleteEventArgs(true, savePath));
                this.BeginInvoke(new Action(() =>
                {
                    try
                    {
                        video.SignalToStop();
                        video.WaitForStop();
                        video.Stop();
                    }
                    catch (Exception)
                    {
                    }
                }));
            }
            catch (Exception ex)
            {
                TriggerReadCompleteEvent(new CompleteEventArgs(false, ex.Message));
            }
        }

        public event CompleteEventHandler CaptureComplete;

        private void TriggerReadCompleteEvent(CompleteEventArgs args)
        {
            var handler = CaptureComplete;
            if (handler != null)
            {
                if (this.InvokeRequired)
                {
                    this.BeginInvoke(handler, args);
                }
                else
                {
                    handler(args);
                }
            }
        }

        public ReturnObjectOfstring RecFphm(string ServiceUrl, string imagePath, int x, int y, int width, int height)
        {
            var serializer = new DataContractJsonSerializer(typeof(ReturnObjectOfstring));
            try
            {
                byte[] imgBytes = File.ReadAllBytes(savePath);
                var imgBase64 = Convert.ToBase64String(imgBytes);
                var endPointAddress = new EndpointAddress(ServiceUrl);
                using (var client = new InvRecognitionServiceClient(binding, endPointAddress))
                {
                    var rtn = client.Recogi(imgBase64, x, y, width, height);
                    //var rtnVal = string.Empty;
                    //using (var stream = new MemoryStream())
                    //{
                    //    serializer.WriteObject(stream, rtn);
                    //    rtnVal = Encoding.UTF8.GetString(stream.GetBuffer());
                    //}
                    //return rtnVal;
                    return rtn;
                }
            }
            catch (Exception ex)
            {
                var rtn = new ReturnObjectOfstring() { Code = "-1", Message = ex.Message };
                //var rtnVal = string.Empty;
                //using (var stream = new MemoryStream())
                //{
                //    serializer.WriteObject(stream, rtn);
                //    rtnVal = Encoding.UTF8.GetString(stream.GetBuffer());
                //}
                //return rtnVal;
                return rtn;
            }
        }

        public string GetCams()
        {
            var videoDevices = new FilterInfoCollection(AForge.Video.DirectShow.FilterCategory.VideoInputDevice);
            var list = new List<string>();
            foreach (FilterInfo item in videoDevices)
            {
                list.Add(item.MonikerString);
            }
            return String.Join(",", list);
        }

        #region IObjectSafety 成员

        private const string _IID_IDispatch = "{00020400-0000-0000-C000-000000000046}";
        private const string _IID_IDispatchEx = "{a6ef9860-c720-11d0-9337-00a0c90dcaa9}";
        private const string _IID_IPersistStorage = "{0000010A-0000-0000-C000-000000000046}";
        private const string _IID_IPersistStream = "{00000109-0000-0000-C000-000000000046}";
        private const string _IID_IPersistPropertyBag = "{37D84F60-42CB-11CE-8135-00AA004BB851}";
        private const int INTERFACESAFE_FOR_UNTRUSTED_CALLER = 0x00000001;
        private const int INTERFACESAFE_FOR_UNTRUSTED_DATA = 0x00000002;
        private const int S_OK = 0;
        private const int E_FAIL = unchecked((int)0x80004005);
        private const int E_NOINTERFACE = unchecked((int)0x80004002);
        private bool _fSafeForScripting = true;
        private bool _fSafeForInitializing = true;

        public int GetInterfaceSafetyOptions(ref Guid riid, ref int pdwSupportedOptions, ref int pdwEnabledOptions)
        {
            int Rslt = E_FAIL;
            string strGUID = riid.ToString("B");
            pdwSupportedOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER | INTERFACESAFE_FOR_UNTRUSTED_DATA;

            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    Rslt = S_OK; pdwEnabledOptions = 0;
                    if (_fSafeForScripting == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_CALLER;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    Rslt = S_OK;
                    pdwEnabledOptions = 0;
                    if (_fSafeForInitializing == true)
                        pdwEnabledOptions = INTERFACESAFE_FOR_UNTRUSTED_DATA;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }
            return Rslt;
        }

        public int SetInterfaceSafetyOptions(ref Guid riid, int dwOptionSetMask, int dwEnabledOptions)
        {
            int Rslt = E_FAIL;
            string strGUID = riid.ToString("B");

            switch (strGUID)
            {
                case _IID_IDispatch:
                case _IID_IDispatchEx:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_CALLER) && (_fSafeForScripting == true))
                        Rslt = S_OK;
                    break;
                case _IID_IPersistStorage:
                case _IID_IPersistStream:
                case _IID_IPersistPropertyBag:
                    if (((dwEnabledOptions & dwOptionSetMask) == INTERFACESAFE_FOR_UNTRUSTED_DATA) && (_fSafeForInitializing == true))
                        Rslt = S_OK;
                    break;
                default:
                    Rslt = E_NOINTERFACE;
                    break;
            }

            return Rslt;
        }

        #endregion
    }
}
